import sys
import mysql.connector
from mysql.connector import Error
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QLineEdit, QMessageBox, QGroupBox,
    QFormLayout, QDoubleSpinBox, QTextEdit, QDialog, QDialogButtonBox
)
from PyQt5.QtGui import QFont
import time
import random  # 添加随机数模块


class DBUtils:
    """数据库工具类"""

    def __init__(self):
        self.connection = None

    def connect(self):
        """连接到MySQL数据库"""
        try:
            if self.connection and self.connection.is_connected():
                return True

            self.connection = mysql.connector.connect(
                host='localhost',
                database='bank system',
                user='root',
                password='1234'
            )
            if self.connection.is_connected():
                # 修复弃用的 get_server_info()
                db_info = self.connection.server_info
                print(f"成功连接到MySQL服务器 (版本 {db_info})")
                return True
            return False
        except Error as e:
            print(f"数据库连接失败: {e}")
            return False

    def disconnect(self):
        """关闭数据库连接"""
        if self.connection and self.connection.is_connected():
            self.connection.close()
            self.connection = None
            print("数据库连接已关闭")

    def execute_query(self, query, params=None, fetch=True):
        """执行SQL查询"""
        cursor = None
        try:
            # 确保连接有效
            if not self.connect():
                print("无法连接到数据库")
                return None

            cursor = self.connection.cursor(dictionary=True)
            cursor.execute(query, params or ())

            if fetch:
                result = cursor.fetchall()
                return result
            else:
                self.connection.commit()
                return True
        except Error as e:
            print(f"查询执行失败: {e}")
            if self.connection:
                self.connection.rollback()
            return None
        finally:
            if cursor:
                cursor.close()


class TransactionManager:
    """交易管理类 - 修复版"""

    def __init__(self, db_utils=None):
        """
        初始化交易管理器
        :param db_utils: DBUtils实例，用于数据库操作
        """
        self.db = db_utils or DBUtils()  # 允许传入外部DBUtils实例或创建新的

    def _generate_trade_id(self):
        """生成唯一交易流水号"""
        return f"TR{int(time.time() * 1000)}{random.randint(100, 999)}"

    def transfer(self, from_card_id, to_card_id, amount, password, remark=None):
        """执行转账操作"""
        # 确保数据库连接有效
        if not self.db.connect():
            return False, "无法连接到数据库"

        if not isinstance(amount, (int, float)) or amount <= 0:
            return (False, "转账金额必须为正数")

        if from_card_id == to_card_id:
            return (False, "不能向自己转账")

        if not self.db.connect():
            return (False, "无法连接到数据库")

        try:
            # 1. 验证转出卡信息
            from_card_query = """
            SELECT balance, pass, IsReportLoss 
            FROM cardInfo 
            WHERE cardID = %s 
            """
            from_card_info = self.db.execute_query(from_card_query, (from_card_id,))

            if not from_card_info or len(from_card_info) == 0:
                return (False, "转出卡不存在")

            from_card_info = from_card_info[0]

            if from_card_info['IsReportLoss'] == '是':
                return (False, "转出卡已挂失")

            if from_card_info['pass'] != password:
                return (False, "转出卡密码错误")

            if from_card_info['balance'] < amount:
                return (False, "转出卡余额不足")

            # 2. 验证转入卡信息
            to_card_query = """
            SELECT IsReportLoss 
            FROM cardInfo 
            WHERE cardID = %s 
            """
            to_card_info = self.db.execute_query(to_card_query, (to_card_id,))

            if not to_card_info or len(to_card_info) == 0:
                return (False, "转入卡不存在")

            to_card_info = to_card_info[0]

            if to_card_info['IsReportLoss'] == '是':
                return (False, "转入卡已挂失")

            # 3. 执行转账操作
            trade_id = self._generate_trade_id()

            # 转出卡扣款
            update_from_query = """
            UPDATE cardInfo 
            SET balance = balance - %s 
            WHERE cardID = %s
            """
            if not self.db.execute_query(update_from_query, (amount, from_card_id), fetch=False):
                return (False, "转出卡更新失败")

            # 转入卡加款
            update_to_query = """
            UPDATE cardInfo 
            SET balance = balance + %s 
            WHERE cardID = %s
            """
            if not self.db.execute_query(update_to_query, (amount, to_card_id), fetch=False):
                return (False, "转入卡更新失败")

            # 记录转出交易
            insert_out_query = """
            INSERT INTO tradeInfo 
            (cardID, tradeDate, tradeType, transactionID, tradeMoney, remark)
            VALUES (%s, NOW(), '转账转出', %s, %s, %s)
            """
            if not self.db.execute_query(
                    insert_out_query,
                    (from_card_id, trade_id, -amount, remark),
                    fetch=False
            ):
                return (False, "转出交易记录失败")

            # 记录转入交易
            insert_in_query = """
            INSERT INTO tradeInfo 
            (cardID, tradeDate, tradeType, transactionID, tradeMoney, remark)
            VALUES (%s, NOW(), '转账转入', %s, %s, %s)
            """
            if not self.db.execute_query(
                    insert_in_query,
                    (to_card_id, trade_id, amount, remark),
                    fetch=False
            ):
                return (False, "转入交易记录失败")

            # 确保所有操作成功
            return (True, f"成功转账 ¥{amount:.2f} 到卡号 {to_card_id}")

        except Exception as e:
            print(f"转账失败: {e}")
            return (False, f"转账失败: {str(e)}")

    def get_transfer_history(self, card_id):
        """获取转账历史记录"""
        if not self.db.connect():
            return None

        query = """
        SELECT * FROM tradeinfo 
        WHERE cardID = %s AND (tradeType = '转账转出' OR tradeType = '转账转入')
        ORDER BY tradeDate DESC
        """
        try:
            return self.db.execute_query(query, (card_id,))
        except Exception as e:
            print(f"查询转账历史失败: {e}")
            return None

    def get_daily_transactions(self, card_id, year, month):
        """
        获取指定月份的每日交易数据

        参数:
            card_id: 银行卡号
            year: 年份
            month: 月份

        返回:
            dict: 按天组织的交易数据，格式为:
                {
                    1: {'income': 100.0, 'expense': 50.0},
                    2: {'income': 0.0, 'expense': 75.0},
                    ...
                }
        """
        # 使用更可靠的连接管理
        connected = self.db.connect()
        if not connected:
            print("数据库连接失败")
            return {}

        try:
            # 计算该月的天数
            if month in [1, 3, 5, 7, 8, 10, 12]:
                days_in_month = 31
            elif month in [4, 6, 9, 11]:
                days_in_month = 30
            else:
                # 2月，考虑闰年
                days_in_month = 29 if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) else 28

            # 初始化结果字典，包含当月每一天
            daily_data = {day: {'income': 0.0, 'expense': 0.0} for day in range(1, days_in_month + 1)}

            # 查询该月所有交易
            query = """
            SELECT 
                DAY(tradeDate) AS day,
                tradeType,
                SUM(ABS(tradeMoney)) AS amount
            FROM tradeinfo
            WHERE cardID = %s
                AND YEAR(tradeDate) = %s
                AND MONTH(tradeDate) = %s
            GROUP BY DAY(tradeDate), tradeType
            ORDER BY day
            """
            params = (card_id, year, month)
            result = self.db.execute_query(query, params)

            if result is None or len(result) == 0:
                return daily_data

            # 处理查询结果
            for row in result:
                day = int(row['day'])
                trade_type = row['tradeType']
                amount = float(row['amount'])

                if day in daily_data:  # 确保日期在有效范围内
                    if trade_type in ['存款', '转账转入']:
                        daily_data[day]['income'] += amount
                    elif trade_type in ['取款', '转账转出']:
                        daily_data[day]['expense'] += amount

            return daily_data

        except Exception as e:
            print(f"获取每日交易数据失败: {e}")
            return {}
        finally:
            # 使用更通用的资源清理方式
            if hasattr(self.db, 'close_connection'):
                self.db.close_connection()
            elif hasattr(self.db, 'close'):
                self.db.close()
            elif hasattr(self.db, 'disconnect'):
                self.db.disconnect()


class CustomerLoginWindow(QWidget):
    """银行卡登录界面"""

    def __init__(self):
        super().__init__()
        self.setWindowTitle("银行卡客户登录")
        self.setFixedSize(400, 250)
        self.transfer_window = None
        self.setup_ui()

    def setup_ui(self):
        """初始化登录界面"""
        layout = QVBoxLayout()
        layout.setSpacing(15)
        layout.setContentsMargins(30, 30, 30, 30)

        # 登录表单
        form_group = QGroupBox("银行卡登录")
        form_layout = QFormLayout()

        self.card_id_input = QLineEdit()
        self.card_id_input.setPlaceholderText("请输入16位银行卡号")
        self.card_id_input.setMaxLength(16)

        self.password_input = QLineEdit()
        self.password_input.setPlaceholderText("请输入6位密码")
        self.password_input.setMaxLength(6)
        self.password_input.setEchoMode(QLineEdit.Password)

        form_layout.addRow("卡号:", self.card_id_input)
        form_layout.addRow("密码:", self.password_input)
        form_group.setLayout(form_layout)

        # 登录按钮
        login_btn = QPushButton("登录")
        login_btn.clicked.connect(self.handle_login)

        # 布局
        layout.addWidget(form_group)
        layout.addWidget(login_btn)
        self.setLayout(layout)

    def handle_login(self):
        """处理登录逻辑"""
        card_id = self.card_id_input.text().strip()
        password = self.password_input.text().strip()

        if len(card_id) != 16 or not card_id.isdigit():
            QMessageBox.warning(self, "错误", "卡号必须为16位数字")
            return

        if len(password) != 6 or not password.isdigit():
            QMessageBox.warning(self, "错误", "密码必须为6位数字")
            return

        # 创建临时数据库连接进行登录验证
        db = DBUtils()
        if not db.connect():
            QMessageBox.critical(self, "错误", "无法连接数据库")
            return

        try:
            query = """
            SELECT cardID, customerID, balance, IsReportLoss 
            FROM cardInfo 
            WHERE cardID = %s AND pass = %s
            """
            result = db.execute_query(query, (card_id, password))

            if not result or len(result) == 0:
                QMessageBox.warning(self, "登录失败", "卡号或密码错误")
                return

            card_info = result[0]

            if card_info['IsReportLoss'] == '是':
                QMessageBox.warning(self, "登录失败", "该卡已挂失，无法登录")
                return

            # 登录成功，打开转账界面
            if self.transfer_window:
                self.transfer_window.close()

            self.transfer_window = TransferWindow(
                card_info['cardID'],
                card_info['customerID'],
                card_info['balance']
            )
            self.transfer_window.show()
            self.hide()

        except Exception as e:
            QMessageBox.critical(self, "错误", f"登录时发生错误: {str(e)}")
        finally:
            db.disconnect()


class TransferWindow(QMainWindow):
    """客户转账主界面"""

    def __init__(self, card_id, customer_id, balance):
        super().__init__()
        self.card_id = card_id
        self.customer_id = customer_id
        self.balance = balance
        self.transaction_manager = TransactionManager()

        self.setWindowTitle(f"银行转账 - 卡号: {card_id}")
        self.setFixedSize(1100, 800)
        self.setup_ui()

    def setup_ui(self):
        """初始化转账界面"""
        central_widget = QWidget()
        layout = QVBoxLayout()
        layout.setSpacing(15)
        layout.setContentsMargins(20, 20, 20, 20)

        # 账户信息显示
        info_group = QGroupBox("账户信息")
        info_layout = QFormLayout()

        self.balance_label = QLabel(f"¥ {self.balance:.2f}")
        self.balance_label.setStyleSheet("font-size: 18px; font-weight: bold;")

        info_layout.addRow("卡号:", QLabel(self.card_id))
        info_layout.addRow("客户ID:", QLabel(str(self.customer_id)))
        info_layout.addRow("当前余额:", self.balance_label)
        info_group.setLayout(info_layout)

        # 转账操作按钮
        btn_group = QGroupBox("转账业务")
        btn_layout = QVBoxLayout()

        self.transfer_btn = QPushButton("发起转账")
        self.history_btn = QPushButton("查看转账记录")
        self.back_btn = QPushButton("退出")

        self.transfer_btn.clicked.connect(self.show_transfer_dialog)
        self.history_btn.clicked.connect(self.show_transfer_history)
        self.back_btn.clicked.connect(self.close)

        btn_layout.addWidget(self.transfer_btn)
        btn_layout.addWidget(self.history_btn)
        btn_layout.addStretch()
        btn_layout.addWidget(self.back_btn)
        btn_group.setLayout(btn_layout)

        # 转账记录显示
        self.transfer_log = QTextEdit()
        self.transfer_log.setReadOnly(True)

        # 布局
        layout.addWidget(info_group)
        layout.addWidget(btn_group)
        layout.addWidget(QLabel("最近转账记录:"))
        layout.addWidget(self.transfer_log)
        central_widget.setLayout(layout)
        self.setCentralWidget(central_widget)

    def show_transfer_dialog(self):
        """显示转账对话框"""
        dialog = QDialog(self)
        dialog.setWindowTitle("转账操作")
        dialog.setFixedSize(400, 300)

        layout = QVBoxLayout()

        # 目标卡号输入
        target_card_input = QLineEdit()
        target_card_input.setPlaceholderText("请输入16位目标卡号")
        target_card_input.setMaxLength(16)

        # 转账金额
        amount_spin = QDoubleSpinBox()
        amount_spin.setRange(0.01, 1000000)
        amount_spin.setPrefix("¥ ")
        amount_spin.setDecimals(2)
        amount_spin.setValue(100.00)

        # 密码验证
        password_input = QLineEdit()
        password_input.setPlaceholderText("请输入6位密码")
        password_input.setMaxLength(6)
        password_input.setEchoMode(QLineEdit.Password)

        # 备注
        remark_input = QLineEdit()
        remark_input.setPlaceholderText("可选备注")

        # 按钮
        btn_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
        btn_box.accepted.connect(lambda: self.handle_transfer(
            dialog,
            target_card_input.text().strip(),
            amount_spin.value(),
            password_input.text().strip(),
            remark_input.text().strip()
        ))
        btn_box.rejected.connect(dialog.reject)

        # 布局
        form = QFormLayout()
        form.addRow("目标卡号:", target_card_input)
        form.addRow("转账金额:", amount_spin)
        form.addRow("交易密码:", password_input)
        form.addRow("备注:", remark_input)

        layout.addLayout(form)
        layout.addWidget(btn_box)
        dialog.setLayout(layout)

        dialog.exec_()

    def handle_transfer(self, dialog, to_card_id, amount, password, remark):
        """处理转账请求"""
        # 基本验证
        if len(to_card_id) != 16 or not to_card_id.isdigit():
            QMessageBox.warning(self, "错误", "目标卡号必须为16位数字")
            return

        if amount <= 0:
            QMessageBox.warning(self, "错误", "转账金额必须大于0")
            return

        if len(password) != 6 or not password.isdigit():
            QMessageBox.warning(self, "错误", "密码必须为6位数字")
            return

        # 执行转账
        success, message = self.transaction_manager.transfer(
            self.card_id, to_card_id, amount, password, remark or None
        )

        if success:
            QMessageBox.information(self, "成功", message)
            self.update_balance()
            self.show_transfer_history()
            dialog.accept()
        else:
            QMessageBox.warning(self, "失败", message)

    def show_transfer_history(self):
        """显示转账历史记录"""
        try:
            history = self.transaction_manager.get_transfer_history(self.card_id)

            if history is None:
                QMessageBox.warning(self, "错误", "获取转账记录失败")
                return

            self.transfer_log.clear()
            if history:
                log_text = "日期\t\t类型\t金额\t备注\n"
                log_text += "-" * 50 + "\n"
                for trans in history:
                    trade_date = trans.get('tradeDate')
                    if isinstance(trade_date, str):
                        date_str = trade_date
                    elif hasattr(trade_date, 'strftime'):
                        date_str = trade_date.strftime('%Y-%m-%d %H:%M')
                    else:
                        date_str = str(trade_date)

                    money = trans.get('tradeMoney', 0)
                    # 格式化金额，显示正负符号
                    sign = '+' if money >= 0 else ''
                    log_text += (
                        f"{date_str}\t"
                        f"{trans.get('tradeType', '未知')}\t"
                        f"{sign}¥{money:.2f}\t"
                        f"{trans.get('remark', '')}\n"
                    )
                self.transfer_log.setPlainText(log_text)
            else:
                self.transfer_log.setPlainText("暂无转账记录")
        except Exception as e:
            QMessageBox.warning(self, "错误", f"显示转账历史时出错: {str(e)}")

    def update_balance(self):
        """更新余额显示"""
        try:
            query = "SELECT balance FROM cardInfo WHERE cardID = %s"
            result = self.transaction_manager.db.execute_query(query, (self.card_id,))
            if result and len(result) > 0:
                self.balance = result[0]['balance']
                self.balance_label.setText(f"¥ {self.balance:.2f}")
        except Exception as e:
            print(f"更新余额失败: {e}")


if __name__ == "__main__":
    app = QApplication(sys.argv)

    # 设置全局字体
    font = QFont()
    font.setFamily("Microsoft YaHei" if sys.platform == 'win32' else "Arial")
    font.setPointSize(10)
    app.setFont(font)

    try:
        window = CustomerLoginWindow()
        window.show()
        sys.exit(app.exec_())
    except Exception as e:
        print(f"程序崩溃: {e}")
        QMessageBox.critical(None, "系统错误", f"程序发生致命错误: {str(e)}")




